package sdk

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"math/rand"
	"net/url"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/astaxie/beego/logs"
)

// 查询参数排序
func strSort(queryMap map[string]interface{}) string {

	var qureys bytes.Buffer
	var keys []string
	for k := range queryMap {
		keys = append(keys, k)
	}

	logs.Debug("qcloud tts sort args:", queryMap)
	// 按key排序
	sort.Strings(keys)

	for _, k := range keys {
		qureys.WriteString(k)
		qureys.WriteString("=")
		v := queryMap[k]
		switch v.(type) {
		case string:
			qureys.WriteString(v.(string))

		case int:
			qureys.WriteString(fmt.Sprintf("%d", v.(int)))

		case int64:
			qureys.WriteString(fmt.Sprintf("%d", v.(int64)))

		case int32:
			qureys.WriteString(fmt.Sprintf("%d", v.(int32)))

		case float32:
			qureys.WriteString(fmt.Sprintf("%.2f", v.(float32)))

		case float64:
			qureys.WriteString(fmt.Sprintf("%.2f", v.(float64)))

		default:
			logs.Error("k:%v wrong type :%v", k)
		}

		qureys.WriteString("&")
	}

	rs := []rune(qureys.String())
	rs_len := len(rs)

	return string(rs[0 : rs_len-1])
}

func createUrl(queryMap map[string]interface{}) string {

	var qureys bytes.Buffer

	for k, v := range queryMap {

		if k == "Text" {
			continue
		}

		qureys.WriteString(k)
		qureys.WriteString("=")

		switch v.(type) {
		case string:
			qureys.WriteString(v.(string))

		case int:
			qureys.WriteString(fmt.Sprintf("%d", v.(int)))

		case int64:
			qureys.WriteString(fmt.Sprintf("%d", v.(int64)))

		case int32:
			qureys.WriteString(fmt.Sprintf("%d", v.(int32)))

		case float32:
			qureys.WriteString(fmt.Sprintf("%.2f", v.(float32)))

		case float64:
			qureys.WriteString(fmt.Sprintf("%.2f", v.(float64)))

		default:
			logs.Error("k:%v wrong type :%v", k)
		}

		qureys.WriteString("&")
	}

	rs := []rune(qureys.String())

	return string(rs[0:])
}

// 查询参数排序
func strSortEncode(queryMap map[string]interface{}) string {

	var keys []string
	for k := range queryMap {
		keys = append(keys, k)
	}

	logs.Debug("qcloud tts sort args:", queryMap)
	// 按key排序
	sort.Strings(keys)
	args := url.Values{}
	for _, k := range keys {

		v := queryMap[k]
		switch v.(type) {
		case string:

			args.Add(k, v.(string))
		case int:

			args.Add(k, fmt.Sprintf("%d", v.(int)))
		case int64:

			args.Add(k, fmt.Sprintf("%d", v.(int64)))
		case int32:

			args.Add(k, fmt.Sprintf("%d", v.(int32)))
		case float32:

			args.Add(k, fmt.Sprintf("%2f", v.(float32)))
		case float64:

			args.Add(k, fmt.Sprintf("%2f", v.(float64)))
		default:
			logs.Error("k:%v wrong type :%v", k)
		}

	}

	return args.Encode()

}

// 请求参数组装
func (c *Client) genQueryStr(target map[string]interface{}) (string, string) {

	c.requstCount++
	target["Action"] = c.action
	target["Region"] = c.region
	target["Nonce"] = genNonce()
	target["SecretId"] = c.secretId
	target["Version"] = c.version
	target["SampleRate"] = "8000"

	//默认模型，必填参数
	if _, ok := target["ModelType"]; !ok {
		target["ModelType"] = "1"
	}

	target["SessionId"] = fmt.Sprintf("%v%d", c.dsid, c.requstCount)

	var t = int(time.Now().Unix())
	target["Timestamp"] = strconv.Itoa(t)

	queryStr := strSort(target)
	reqUrl := createUrl(target)
	//logs.Debug("queryStr is： ", queryStr)
	return queryStr, reqUrl

}

// 生成随机数
func genNonce() string {

	var t = time.Now().Unix()

	// 随机数生成器
	source := rand.NewSource(t)
	r := rand.New(source)

	num := r.Intn(10000)

	return strconv.Itoa(num)
}

// 生成签名串
func (c *Client) genSign(serverUrl, secretKey string) string {

	var url string
	rs := []rune(serverUrl)

	if strings.HasPrefix(serverUrl, "https") {
		url = "GET" + string(rs[8:])
	} else {
		url = "GET" + string(rs[7:])
	}

	hmac := hmac.New(sha1.New, []byte(secretKey))
	hmac.Write([]byte(url))
	encoded_byte_arr := hmac.Sum([]byte(""))

	var signature = base64.StdEncoding.EncodeToString(encoded_byte_arr)

	//logs.Debug("sign is: ", signature)
	return signature
}

// 生成请求url
func (c *Client) genQueryUrl(serverUrl string, queryStr string) string {

	var queryUrl bytes.Buffer
	queryUrl.WriteString(serverUrl)
	//queryUrl.WriteString(c.appId)
	queryUrl.WriteString("?")
	queryUrl.WriteString(queryStr)

	//logs.Debug("url is: ", queryUrl.String())
	return queryUrl.String()
}

func (c *Client) getAuthorization(uri string) string {

	return ""
}

func sha1_str(s string) string {
	h := sha1.New()
	io.WriteString(h, s)
	r := h.Sum(nil)
	return hex.EncodeToString(r[:])
}

func hmac_sha1_str(str1, str2 string) string {
	mac := hmac.New(sha1.New, []byte(str1))
	mac.Write([]byte(str2))
	r := mac.Sum(nil)
	return hex.EncodeToString(r[:])
}

// 查询参数排序
func strSortFlow(args ttsParam) string {

	var signStr bytes.Buffer
	var keys []string
	argMap := make(map[string]interface{})

	t := reflect.TypeOf(args)
	v := reflect.ValueOf(args)

	for k := 0; k < t.NumField(); k++ {
		key := fmt.Sprintf("%s", t.Field(k).Name)
		keys = append(keys, key)

		//logs.Debug("参数:%v", key)

		argMap[key] = v.Field(k).Interface()
	}

	// 按key排序
	sort.Strings(keys)

	for _, k := range keys {

		valueStr := fmt.Sprintf("%v", argMap[k])
		signStr.WriteString(k)
		signStr.WriteString("=")
		signStr.WriteString(valueStr)
		signStr.WriteString("&")
	}

	rs := []rune(signStr.String())
	rs_len := len(rs)

	return string(rs[0 : rs_len-1])
}

// 生成签名串
func (c *Client) genFlowSign(method, serverUrl, authStr, secretKey string) string {

	var url string
	rs := []rune(serverUrl)

	if strings.HasPrefix(serverUrl, "https") {
		url = method + string(rs[8:])
	} else {
		url = method + string(rs[7:])
	}

	url += "?" + authStr
	logs.Debug("签名串:%v", url)
	hmac := hmac.New(sha1.New, []byte(secretKey))
	hmac.Write([]byte(url))
	encoded_byte_arr := hmac.Sum([]byte(""))

	return base64.StdEncoding.EncodeToString(encoded_byte_arr)
}
